package org.yzhzc.common.security.handler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.yzhzc.common.core.domain.R;
import org.yzhzc.common.core.enums.ResultCode;
import org.yzhzc.common.security.exception.ServiceException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Collection;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 处理应用中的各种异常，返回统一格式的响应
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 将错误集合转换为字符串
     *
     * @param collection 错误集合
     * @param function   转换函数
     * @param delimiter  分隔符
     * @param <E>       集合元素类型
     * @return 合并后的字符串
     */
    private <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
        if (CollUtil.isEmpty(collection)) {
            return StrUtil.EMPTY; // 如果集合为空，返回空字符串
        }
        return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); // 连接字符串
    }

    /**
     * 处理请求方法不支持的异常
     *
     * @param e      HttpRequestMethodNotSupportedException 异常对象
     * @param request HttpServletRequest 请求对象
     * @return 统一的失败响应
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
                                                    HttpServletRequest request) {
        String requestURI = request.getRequestURI(); // 获取请求URI
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); // 记录错误日志
        return R.fail(ResultCode.ERROR); // 返回统一失败响应
    }

    /**
     * 处理业务异常
     *
     * @param e      ServiceException 业务异常对象
     * @param request HttpServletRequest 请求对象
     * @return 统一的失败响应
     */
    @ExceptionHandler(ServiceException.class)
    public R<?> handleServiceException(ServiceException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI(); // 获取请求URI
        ResultCode resultCode = e.getResultCode(); // 获取业务异常的结果代码
        log.error("请求地址'{}',发生业务异常: {}", requestURI, resultCode.getMsg(), e); // 记录错误日志
        return R.fail(resultCode); // 返回业务异常响应
    }

    /**
     * 处理参数绑定异常
     *
     * @param e BindException 参数绑定异常对象
     * @return 统一的失败响应
     */
    @ExceptionHandler(BindException.class)
    public R<Void> handleBindException(BindException e) {
        log.error(e.getMessage()); // 记录异常信息
        String message = join(e.getAllErrors(),
                DefaultMessageSourceResolvable::getDefaultMessage, ", "); // 合并错误信息
        return R.fail(ResultCode.FAILED_PARAMS_VALIDATE.getCode(), message); // 返回参数验证失败响应
    }


    /**
     * 拦截运行时异常
     *
     * @param e      RuntimeException 运行时异常对象
     * @param request HttpServletRequest 请求对象
     * @return 统一的失败响应
     */
    @ExceptionHandler(RuntimeException.class)
    public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI(); // 获取请求URI
        log.error("请求地址'{}',发生运行时异常.", requestURI, e); // 记录错误日志
        return R.fail(ResultCode.ERROR); // 返回统一失败响应
    }

    /**
     * 处理系统级别异常
     *
     * @param e      Exception 系统异常对象
     * @param request HttpServletRequest 请求对象
     * @return 统一的失败响应
     */
    @ExceptionHandler(Exception.class)
    public R<?> handleException(Exception e, HttpServletRequest request) {
        String requestURI = request.getRequestURI(); // 获取请求URI
        log.error("请求地址'{}',发生异常.", requestURI, e); // 记录错误日志
        return R.fail(ResultCode.ERROR); // 返回统一失败响应
    }
}
